var SUBPART_PREFIXES = [
    'SHOW MAP',
    'ROUTE TABLE',
];

var g_report = {};

$(document).ready(function() {
    var source = $(document.body).text();
    $(document.body).html('');
    loadBugReport(source);
});

function loadBugReport(source) {
    g_report = {parts:[]};

    var remainingSource = source;
    var next = 0;

    var firstIndex_ = function(i1, i2) {
        if (i1 < 0 || i2 < 0) {
            return Math.max(i1, i2);
        } else {
            return Math.min(i1, i2);
        }
    }

    var loadNextPart_ = function() {
        next = firstIndex_(
            remainingSource.search(/\n-{6}\s+[A-Z]+/),
            remainingSource.search(/\nDUMP OF SERVICE /));
        if (next < 0) {
            addPart(remainingSource);
            buildUI();
            return;
        }
        addPart(remainingSource.substr(0, next));
        remainingSource = remainingSource.substr(next + 1);
        setTimeout(loadNextPart_, 0);
    };

    loadNextPart_();
}

function addPart(partContents) {
    // Parse heading
    var part = {subParts:[]};
    var firstLine = partContents.match(/^.*/);
    var headingMatch =
        partContents.match(/^-{6}\s+([A-Z][A-Za-z0-9-& ]+)\s*(\(.+\))?\s+-{6}/) ||
            partContents.match(/^DUMP OF SERVICE (\w+)/);
    var isSubpart = false;

    if (headingMatch) {
        part.title = headingMatch[1].replace(/^ +/,'').replace(/ +$/,'');
        for (var i in SUBPART_PREFIXES) {
            if (part.title.indexOf(SUBPART_PREFIXES[i]) == 0) {
                isSubpart = true;
                break;
            }
        }
        if (partContents.indexOf('DUMP OF SERVICE') == 0) {
            isSubpart = true;
        }
        part.subtitle = headingMatch[2] || '';
        part.contents = partContents;

    } else {
        if (g_report.parts.length == 0) {
            part.title = "Preamble / Build Info";
        }
        part.unparsedContents = partContents;
    }

    if (isSubpart && g_report.parts.length > 0) {
        var parentPart = g_report.parts[g_report.parts.length - 1];
        parentPart.subParts.push(part);

    } else {
        g_report.parts.push(part);
    }

    onPartLoaded(part);
}

function onPartLoaded(part) {
    if (part.title == 'PROCESSES') {
        g_report.processTable = {};
        var lines = part.contents.split(/\n/);
        for (var i in lines) {
            var items = lines[i].split(/\s+/);
            // items[1] should be the PID
            // items[n] should be the process name
            if (items.length >= 3 && items[1].match(/[0-9]+/)) {
                g_report.processTable[parseInt(items[1], 10)] = items[items.length - 1];
            }
        }
    }
}

function buildUI() {
    // Build layout
    var $container = $('<div>')
        .addClass('bugreport')
        .appendTo('body');
    $('<div>')
        .addClass('bugreport-sidebar')
        .appendTo($container);
    $('<div>')
        .addClass('bugreport-detail')
        .append($('<div>').addClass('bugreport-toolbar'))
        .append($('<div>').addClass('bugreport-content'))
        .appendTo($container);

    populateSidebar();

    openPart(g_report.parts[0]);
}

function populateSidebar() {
    // Populate sidebar
    var $tree = $('<ul>')
        .addClass('bugreport-tree')
        .appendTo('.bugreport-sidebar');

    var buildPartTree_ = function($parent, part) {
        part.$node = $('<li>')
            .addClass('bugreport-part')
            .appendTo($parent);
        var $titleNode = $('<div>')
            .addClass('bugreport-tree-title')
            .text(part.title)
            .click(function() {
                openPart(part);
            })
            .appendTo(part.$node);
        $('<span>')
            .addClass('bugreport-tree-subtitle')
            .text((part.subtitle ? (part.subtitle + ', ') : '')
            + humanizeFileSize((part.contents || part.unparsedContents || '').length))
            .appendTo($titleNode);
        if (part.subParts.length) {
            part.$node.addClass('bugreport-has-children');
            var $subpartContainer = $('<ul>')
                .appendTo(part.$node);
            for (var i in part.subParts) {
                buildPartTree_($subpartContainer, part.subParts[i]);
            }
        }
    }

    for (var i = 0; i < g_report.parts.length; i++) {
        buildPartTree_($tree, g_report.parts[i]);
    }
}

function openPart(part) {
    if (part.subParts.length) {
        if (part.$node.hasClass('bugreport-expanded')) {
            $('.bugreport-part').removeClass('bugreport-expanded');
        } else {
            $('.bugreport-part').removeClass('bugreport-expanded');
            part.$node.addClass('bugreport-expanded');
        }
    }

    $('.bugreport-part').removeClass('bugreport-selected');
    part.$node.addClass('bugreport-selected');

    var renderer = defaultRenderer;
    for (var k in RENDERERS_BY_PREFIX) {
        if (part.title.indexOf(k) == 0) {
            renderer = RENDERERS_BY_PREFIX[k];
            break;
        }
    }

    $('.bugreport-toolbar').empty();
    renderer(part, $('.bugreport-content').empty());
}

var RENDERERS_BY_PREFIX = {
    'SYSTEM LOG': systemLogRenderer
};

function defaultRenderer(part, $dest) {
    var lines = (part.contents || part.unparsedContents || '[Empty]').split(/\n/);
    for (var i in lines) {
        $('<pre>')
            .text(lines[i])
            .appendTo($dest);
    }

    addRegexGrepToToolbar();
}

function systemLogRenderer(part, $dest) {
    addRegexGrepToToolbar();

    var $minimumSeverityControl = $('<select>')
        .append($('<option>').attr('value', '0').text('No minimum severity'))
        .append($('<option>').attr('value', '1').text('Warnings'))
        .append($('<option>').attr('value', '2').text('Errors'))
        .appendTo('.bugreport-toolbar')
        .change(function() {
            reRender_();
        });

    var reRender_ = function() {
        $dest.empty();
        var minimumSeverity = parseInt($minimumSeverityControl.val(), 10);

        var lines = part.contents.split(/\n/);
        for (var i in lines) {
            var line = lines[i];
            var items = line.split(/\s+/, 5);
            // items[2] is the PID
            // items[4] is the message type
            var lineClass = '';
            if (items[4] == 'E') {
                lineClass = 'bugreport-system-log-error';
            } else if (items[4] == 'W') {
                if (minimumSeverity > 1) continue;
                lineClass = 'bugreport-system-log-warn';
            } else if (items[4] == 'D') {
                if (minimumSeverity > 0) continue;
                lineClass = 'bugreport-system-log-debug';
            } else {
                if (minimumSeverity > 0) continue;
                lineClass = 'bugreport-system-log-other';
            }
            // if (g_report.processTable && items[2] in g_report.processTable) {
            //   line = g_report.processTable[items[2]] + ' ' + line;
            // }
            $('<pre>')
                .text(line)
                .addClass(lineClass)
                .appendTo($dest);
        }
    };

    reRender_();
}

function addRegexGrepToToolbar() {
    $('<input>')
        .appendTo('.bugreport-toolbar')
        .attr('placeholder', 'grep (regex)')
        .attr('size', 40)
        .keydown(function() {
            var me = this;
            setTimeout(function() {
                try {
                    var reString = $(me).val();
                    var re = reString ? new RegExp(reString, 'i') : null;

                    var matching = true;
                    var section = 0;
                    $('.bugreport-content pre').each(function() {
                        $(this).removeClass("match");
                        $(this).removeClass("nomatch");
                        $(this).removeClass("bugreport-collapsible");

                        if (this.innerHTML.match(re) || re == null) {
                            $(this).addClass("match");
                            matching = true;
                        } else {
                            if (matching) {
                                ++section;
                                matching = false;
                                var expando = $('<span>')
                                    .text('Show lines that don\'t match')
                                    .attr('section', section)
                                    .addClass('bugreport-expando');
                                expando.on('click', function(event) {
                                    var selectSection = '.bugreport-content pre[section="' + $(this).attr('section') + '"]';

                                    $(selectSection).toggle();
                                });
                                $(this).before(expando);
                            }
                            $(this).addClass("nomatch");
                            $(this).attr('section', section);
                            $(this).css('display', 'none');
                        }
                    });

                    $(me).css('color', 'black');
                } catch (e) {
                    $(me).css('color', 'red');
                }
            }, 0);
        });
}

function humanizeFileSize(bytes) {
    var kilobyte = 1024;
    var megabyte = kilobyte * 1024;
    var gigabyte = megabyte * 1024;
    var terabyte = gigabyte * 1024;

    if ((bytes >= 0) && (bytes < kilobyte)) {
        return bytes + ' bytes';
    } else if ((bytes >= kilobyte) && (bytes < megabyte)) {
        return (bytes / kilobyte).toFixed(0) + ' KB';
    } else if ((bytes >= megabyte) && (bytes < gigabyte)) {
        return (bytes / megabyte).toFixed(0) + ' MB';
    } else {
        return bytes + ' bytes';
    }
}

$(document.body).keydown(function(evt) {
    if (evt.target && evt.target.tagName.toLowerCase() == 'input') {
        return;
    }

    var scroll = false;
    if (evt.which == 75) { // K
        $('.bugreport-part.bugreport-selected').prev().find('.bugreport-tree-title').first().trigger('click');
        scroll = true;
    } else if (evt.which == 74) { // J
        $('.bugreport-part.bugreport-selected').next().find('.bugreport-tree-title').first().trigger('click');
        scroll = true;
    }

    if (scroll) {
        setTimeout(function() {
            var $sidebar = $('.bugreport-sidebar');
            var $part = $('.bugreport-part.bugreport-selected');
            $('.bugreport-sidebar').animate({
                scrollTop: $part.offset().top - $sidebar.offset().top + $sidebar.scrollTop() - 40
            }, 'fast');
        }, 0);
    }
});